package com.xuan.friend.service.user.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.xuan.common.core.constants.Constants;
import com.xuan.common.core.domain.TableDataInfo;
import com.xuan.common.core.enums.ContestZSetType;
import com.xuan.common.core.exception.BusinessException;
import com.xuan.common.core.utils.ThreadLocalUtils;
import com.xuan.friend.domain.contest.Contest;
import com.xuan.friend.domain.contest.dto.ContestQueryDTO;
import com.xuan.friend.domain.contest.vo.ContestVo;
import com.xuan.friend.domain.user.UserContest;
import com.xuan.friend.manager.ContestCacheManager;
import com.xuan.friend.mapper.user.UserContestMapper;
import com.xuan.friend.mapper.contest.ContestMapper;
import com.xuan.friend.service.user.UserContestService;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.ZonedDateTime;
import java.util.List;

/**
 * @author ASUS
 * @description 针对表【tb_user_contest(用户-竞赛 关系表)】的数据库操作Service实现
 * @createDate 2024-11-26 22:28:59
 */
@Service
public class UserContestServiceImpl extends ServiceImpl<UserContestMapper, UserContest>
        implements UserContestService {

    @Resource
    private UserContestMapper userContestMapper;

    @Resource
    private ContestMapper contestMapper;


    @Resource
    private ContestCacheManager contestCacheManager;


    @Override
    public int enterContest(Long contestId, String token) {
        // 1. 查看竞赛是否存在
        Contest contest = getContest(contestId);
        // 2. 竞赛未发布,不允许报名
        if (!Constants.TRUE.equals(contest.getStatus())) {
            throw new BusinessException("竞赛不存在,报名失败");
        }
        // 3. 竞赛开始后不能报名
        if (contest.getStartTime().isBefore(LocalDateTime.now())) {
            throw new BusinessException("竞赛已开始,无法报名");
        }
        // 4. 不能重复报名
        Long userId = ThreadLocalUtils.get(Constants.USER_ID, Long.class);
        if (userId == null) {
            throw new BusinessException("未登录");
        }
        Long count = userContestMapper.selectCount(new LambdaQueryWrapper<UserContest>()
                .eq(UserContest::getUserId, userId)
                .eq(UserContest::getContestId, contestId));
        if (count != null && count > 0) {
            throw new BusinessException("已报名竞赛,不能重复报名");
        }
        // 5. 往数据库和 redis 中插入数据
        contestCacheManager.addUserContestCache(userId, contestId);
        UserContest userContest = new UserContest();
        userContest.setUserId(userId);
        userContest.setContestId(contestId);
        return userContestMapper.insert(userContest);
    }

    @Override
    public TableDataInfo redisListContest(ContestQueryDTO contestQueryDTO) {
        contestQueryDTO.setType(ContestZSetType.USER_CONTEST.getValue());       // 手动设置竞赛类型
        Integer type = contestQueryDTO.getType();
        Long userId = ThreadLocalUtils.get(Constants.USER_ID, Long.class);      // 获取 userId

        // 1. 拿到 userId ,从 redis 查询已加入的 contestId
        Long total = contestCacheManager.getContestZSetSize(type, userId, contestQueryDTO);
        List<ContestVo> contestVoList;
        if (total == null || total <= 0) {
            // redis 中没有缓存数据,从数据库中查询
            PageHelper.startPage(contestQueryDTO.getPageNum(), contestQueryDTO.getPageSize());
            contestVoList = userContestMapper.listUserContest(userId);
            contestCacheManager.refreshContestCache(type, userId);     // 刷新数据到缓存中
            total = new PageInfo(contestVoList).getTotal();
        } else {
            // 从 redis 中查询对应的数据
            contestVoList = contestCacheManager.getContestVoList(contestQueryDTO, userId);
            // 如果出现异常情况, 刷新缓存后 redis 中的数据会发生变化, 重新获取
            total = contestCacheManager.getContestZSetSize(type, userId, contestQueryDTO);
        }
        return TableDataInfo.success(contestVoList, total);
    }


    private Contest getContest(Long contestId) {
        Contest contest = contestMapper.selectById(contestId);
        if (contest == null) {
            throw new BusinessException("竞赛不存在");
        }
        return contest;
    }


}




